import type { Entity } from './types'

export class Collection<T extends Entity> {
  public idList: string[]
  public list: T[]
  public map: Record<string, T>

  public constructor(lst: T[]) {
    this.idList = lst.map((e) => e.id)
    this.list = lst
    const map: Record<string, T> = {}
    for (const e of lst) {
      map[e.id] = e
    }
    this.map = map
  }

  public getById(id: string): T | undefined {
    return this.map[id]
  }
}

export class ModelSet {
  private data: Record<string, Collection<Entity>> = {}

  public putModel<T extends Entity>(type: string, lst: T[]) {
    this.data[type] = new Collection(lst)
  }

  public getEntityIdList(type: string): string[] {
    return this.data[type].idList
  }

  public getEntityList<T extends Entity = Entity>(type: string): T[] {
    return this.data[type].list as T[]
  }

  public getEntityMap<T extends Entity = Entity>(type: string): Record<string, T> {
    return this.data[type].map as Record<string, T>
  }

  public getEntity<T extends Entity = Entity>(type: string, id: string): T | undefined {
    const col = this.data[type]
    if (!col) {
      return undefined
    }
    return col.getById(id) as T | undefined
  }
}
export interface EntityType {
  type: string
  typeName: string
}

export const entityTypeList: EntityType[] = []
const entityTypes: Record<string, EntityType> = {}
const modelSet = new ModelSet()

export function putEntityType<E extends Entity>({
  type,
  typeName,
  data
}: EntityType & { data: E[] }) {
  if (type in entityTypes) {
    throw Error(`${type} 已经存在`)
  }
  const eType = { type, typeName }
  entityTypes[type] = eType
  entityTypeList.push(eType)
  modelSet.putModel(type, data)
}
export function getEntityType(type: string): EntityType | undefined {
  return entityTypes[type]
}

export function getEntityIdList(type: string): string[] {
  return modelSet.getEntityIdList(type)
}

export function getEntityList<T extends Entity = Entity>(type: string): T[] {
  return modelSet.getEntityList<T>(type)
}

export function getEntityMap<T extends Entity = Entity>(type: string): Record<string, T> {
  return modelSet.getEntityMap<T>(type)
}

export function getEntity<T extends Entity = Entity>(type: string, id: string): T | undefined {
  return modelSet.getEntity(type, id)
}
